/*
 * Copyright 2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jp.co.cij.grails.scaffolding;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.grails.commons.GrailsDomainClass;
import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
import org.codehaus.groovy.grails.validation.ConstrainedProperty;

import com.google.api.translate.Language;
import com.google.api.translate.Translate;

/**
 * generate and transrate messages
 * 
 * @author Shiro Kasahara
 */
public class GrailsMessageTemplateGenerator {

	static final Log LOG = LogFactory
			.getLog(GrailsMessageTemplateGenerator.class);

	// private static final List<string> languages = Language.validLanguages;
	private static final List<String> LANGS = Arrays.asList(new String[] {
			"de", "es", "fr", "it", "ja", "nl", "pt", "ru", "zh-CN", });

	private void generateTemplates() {
		String path = "grails-app/i18n/scaffold-ex.properties";
		File file = new File(path);

		Properties props = new Properties();
		loadProperties(props, file);

		Iterator<String> i = LANGS.iterator();
		while (i.hasNext()) {
			generateTemplate((Properties) props.clone(), i.next());
		}
	}

	private void generateTemplate(Properties props, String lang) {
		String path = "grails-app/i18n/scaffold-ex_" + lang + ".properties";
		File file = new File(path);

		Iterator<Object> i = props.keySet().iterator();
		while (i.hasNext()) {
			String key = i.next().toString();
			props.setProperty(key, translate(props.getProperty(key), lang));
		}
		storeProperties(props, file);
	}

	public void generateTemplates(GrailsDomainClass dc) {
		for (String lang : LANGS) {
			generateTemplate(dc, lang);
		}
		generateTemplate(dc, null);
	}

	private void loadProperties(Properties props, File file) {
		InputStream is = null;
		try {
			is = new FileInputStream(file);
			props.load(is);
			Iterator<Object> i = props.keySet().iterator();
			while (i.hasNext()) {
				String key = i.next().toString();
				props.setProperty(key, new String(props.getProperty(key)
						.getBytes("ISO-8859-1"), "UTF-8"));
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
				}
			}
		}
	}

	private void storeProperties(Properties props, File file) {
		Iterator<Object> i = props.keySet().iterator();
		List<String> keyList = new ArrayList<String>();
		while (i.hasNext()) {
			keyList.add(i.next().toString());
		}
		Collections.sort(keyList);

		PrintWriter pw = null;
		try {
			pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(
					file), "UTF-8"));
			for (String key : keyList) {
				pw.println(key + "=" + props.getProperty(key));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
		} finally {
			if (pw != null) {
				pw.close();
			}
		}

	}

	private void generateTemplate(GrailsDomainClass dc, String _lang) {
		String dcName = dc.getPropertyName();
		String path = null;
		String lang = _lang;
		if (_lang == null) {
			path = "grails-app/i18n/scaffold-ex.properties";
			lang = Language.ENGLISH;
		} else {
			path = "grails-app/i18n/scaffold-ex_" + _lang + ".properties";
		}

		LOG.info("Generating messages (" + lang + ") for domain class [${domainClass.fullName}]");

		File file = new File(path);
		if (!file.exists()) {
			generateTemplates();
		}

		Properties props = new Properties();
		loadProperties(props, file);
		Iterator<Object> i = props.keySet().iterator();
		String keyPrefix = dcName + ".";
		while (i.hasNext()) {
			Object key = i.next();
			if (keyPrefix.equals(key)) {
				props.remove(key);
			}
		}

		String naturalName = dc.getNaturalName();
		props.setProperty(dcName + ".create", translate(
				"Create " + naturalName, lang));
		props.setProperty(dcName + ".edit", translate("Edit " + naturalName,
				lang));
		props.setProperty(dcName + ".new",
				translate("New " + naturalName, lang));
		props.setProperty(dcName + ".show", translate("Show " + naturalName,
				lang));
		props.setProperty(dcName + ".list", translate(naturalName + " List",
				lang));
		props.setProperty(dcName + ".search", translate(
				naturalName + " Search", lang));
		props.setProperty(dcName + ".created", translate(
				naturalName + " _0 created", lang).replaceFirst("_0", " {0} "));
		props.setProperty(dcName + ".updated", translate(
				naturalName + " _0 updated", lang).replaceFirst("_0", " {0} "));
		props.setProperty(dcName + ".deleted", translate(
				naturalName + " _0 deleted", lang).replaceFirst("_0", " {0} "));
		props.setProperty(dcName + ".not.found", translate(
				naturalName + " not found with id _0", lang).replaceFirst("_0",
				" {0} "));

		GrailsDomainClassProperty[] properties = dc.getProperties();
		Map<?, ?> constrainedProperties = dc.getConstrainedProperties();
		for (GrailsDomainClassProperty property : properties) {
			String propertyName = property.getName();
			if ("version".equals(property.getName())) {
				continue;
			}
			props.setProperty(dcName + "." + propertyName, translate(property
					.getNaturalName(), lang));
			ConstrainedProperty constrainedProperty = (ConstrainedProperty) constrainedProperties
					.get(propertyName);
			if (constrainedProperty != null) {
				List<?> inList = constrainedProperty.getInList();
				if (inList != null) {
					for (Object obj : inList) {
						String message = obj.toString();
						props.setProperty(dcName + "." + propertyName + "."
								+ message, translate(message, lang));
					}
				}
			}
		}
		storeProperties(props, file);
	}

	private String translate(String message, String lang) {
		try {
			if (!Language.validLanguages.contains(lang)
					|| Language.ENGLISH.equals(lang)) {
				return message;
			}
			return Translate.translate(message, Language.ENGLISH, lang);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
}
